
(defun clojure-json-to-map ()
  "tranform the data in the region into clojure's map"
  (interactive)
  (insert (replace-regexp-in-string 
           "\" *: *\\([\"0-9-\\[\\{]\\)" 
           "\" \\1" 
           (delete-and-extract-region (region-beginning) (region-end)))))

(defun my-select-indside-braces ()
  (interactive)
  (let (p1 p2)
    (skip-chars-backward "^{")
    (setq p1 (point))
    (skip-chars-forward "^}")
    (setq p2 (point))
    
    (goto-char p1)
    (push-mark p2)
    (setq mark-active t)
    ))

(defun clojure-select-json-block ()
  (interactive)
  (let (p1 p2 (deepth 0) )
    (skip-chars-backward "^{")
    (setq p1 (point))
    (skip-chars-forward "^}")
    (setq p2 (point))
    ))

(defun parent-directorys ()
  "return self and parent directorys"
  (let (dirs (current-dir default-directory))
    (while (not (string-equal "/" current-dir))
      (setq dirs (cons current-dir dirs))
      (setq current-dir (file-name-directory (directory-file-name current-dir))))
    (setq dirs (cons "/" dirs))
    dirs))

(defun clojure-lein-prj-root (dir)
  "test if the directory is the root of lein project"
  (let ((files (directory-files dir)))
    (if (and (seq-contains files "src")
             (seq-contains files "project.clj"))
        dir
      nil)))

(defun clojure-lein-prj-source-root (dir)
  (when-let ((prj-root (clojure-lein-prj-root dir)))
    (file-truename (concat prj-root "src/"))))

;; project-current nil sometimes
(defun clojure-source-root-directory-backup ()
  "return the source root directory of current project ,
 only support lein project now"
  (when-let ((project-root (cdr (project-current))))
    (or (clojure-lein-prj-source-root project-root))))

(defun clojure-source-root-directory ()
  "return the source root directory of current project ,
 only support lein project now"
  (let ((dirs (parent-directorys))
        (root nil))
    (while (not root)
      (setq root (or (clojure-lein-prj-source-root (car dirs))))
      (setq dirs (cdr dirs)))
    root))

(defun clojure-current-project-namespaces (src-root)
  "list all namespaces in current project"
  (when (not src-root) (error "not in a valid project path"))
  (let ((files (seq-filter (lambda (f) 
                             (string-match "\\.clj" f)) 
                           (directory-files-recursively src-root ".*")))
        (regex-src-root (replace-regexp-in-string "\\." "\\\\." src-root)))
    (let ((ns-lists (mapcar 
                     (lambda (f)
                       (split-string 
                        (replace-regexp-in-string
                         "_" "-" (replace-regexp-in-string 
                                  regex-src-root "" (replace-regexp-in-string 
                                                     "\\.clj" "" f))) 
                        "/"))
                     files))
          (namespaces '()))
      (while ns-lists
        (let ((ns-l (car ns-lists))
              (ns nil))
          (while ns-l
            (setq ns (concat ns (if ns "." "") (car ns-l)))
            (setq namespaces (cons ns namespaces))
            (setq ns-l (cdr ns-l)))
          (setq ns-lists (cdr ns-lists))))
      (seq-uniq namespaces 'string-equal))))

(defun clojure-newfile (namespace extension)
  "create file by namespace and extension"
  (let ((filename (concat (clojure-source-root-directory)
                          (replace-regexp-in-string 
                           "-" "_" (replace-regexp-in-string "\\." "/" namespace))
                          "." extension))
        (buf (generate-new-buffer namespace)))
    (with-current-buffer buf
      (insert "(ns " namespace ")")
      (write-file filename t))
    (switch-to-buffer buf)))

(defun clojure-new-namespace ()
  "clojure new name-space"
  (interactive)
  (let ((namespace (ido-completing-read 
                    "namespace:" 
                   (clojure-current-project-namespaces (clojure-source-root-directory))))
        (extension "clj"))
    (clojure-newfile namespace extension)))

